home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / C⁄C++ / Xconq 7.0d37 / source / x11 / xcmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-02  |  37.4 KB  |  1,856 lines  |  [TEXT/KAHL]

  1. /* Commands for the X11 interface to Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. #include "conq.h"
  11. #include "xconq.h"
  12. extern int zoom_in_out PROTO ((Side *side, Map *map, int which));
  13.  
  14. /* The command table is an array of all the commands. */
  15.  
  16. typedef struct cmdtab {
  17.     char fchar;                 /* character to match against */
  18.     char *name;                 /* Full name of command */
  19.     char *argtypes;
  20.     void (*fn)();                /* pointer to command's function */
  21.     char *help;                 /* short documentation string */
  22. } CmdTab;
  23.  
  24. static void execute_named_command PROTO ((Side *side, Map *map, char *cmdstr));
  25. static int execute_named_command_from_table PROTO ((Side *side, Map *map,
  26.                             char *cmdstr,
  27.                             CmdTab *cmdtab));
  28. static void describe_commands PROTO ((int arg, char *key, char *buf));
  29. static void describe_command_table PROTO ((int arg, char *key, char *buf,
  30.                        CmdTab *cmdtab));
  31. static void x_build PROTO ((Side *side, Map *map, int cancel));
  32. static void x_distance PROTO ((Side *side, Map *map, int cancel));
  33. static void x_move_look PROTO ((Side *side, Map *map));
  34. static void x_move_dir PROTO ((Side *side, Map *map, Unit *unit));
  35. static void x_message PROTO ((Side *side, Map *map, int cancel));
  36. static void x_move_to PROTO ((Side *side, Map *map, int cancel));
  37. static void x_name PROTO ((Side *side, Map *map, int cancel));
  38. static void x_others PROTO ((Side *side, Map *map, int cancel));
  39. static void x_resign PROTO ((Side *side, Map *map, int cancel));
  40. static void x_resign_2 PROTO ((Side *side, Map *map, int cancel));
  41. static void x_leave_game PROTO ((Side *side, Map *map, int cancel));
  42. static void x_kill_game PROTO ((Side *side, Map *map, int cancel));
  43. static void x_save_2 PROTO ((Side *side, Map *map, int cancel));
  44. static void x_save_1 PROTO ((Side *side, Map *map, int cancel));
  45. static void x_save_1_1 PROTO ((Side *side, Map *map, int cancel));
  46. static void save_the_game PROTO ((Side *side));
  47. static void cmd_error PROTO ((Side *side, char *fmt, ...));
  48.  
  49. char tmpkey;
  50.  
  51. Map *tmpmap;
  52.  
  53. #define C(c) ((c)-0x40)
  54.  
  55. #undef DEF_CMD
  56. #define DEF_CMD(LETTER,NAME,ARGS,FN,HELP) { LETTER, NAME, ARGS, FN, HELP },
  57.  
  58. /* Define a table of generic Xconq commands. */
  59.  
  60. CmdTab commands[] = {
  61.  
  62. #include "cmd.def"
  63.  
  64.   { 0, NULL, NULL, NULL, NULL }
  65. };
  66.  
  67. /* Define a table of additional X-specific commands. */
  68.  
  69. CmdTab xcommands[] = {
  70.  
  71. #include "xcmd.def"
  72.  
  73.   { 0, NULL, NULL, NULL, NULL }
  74. };
  75.  
  76. /* Search in command table and execute function if found, complaining if
  77.    the command is not recognized.  Many commands operate on the "current
  78.    unit", and all uniformly error out if there is no current unit, so put
  79.    that test here. */
  80.  
  81. static int execute_command_from_table PROTO ((Side *side, Map *map, CmdTab *cmdtab));
  82.  
  83. void
  84. execute_command(side, map)
  85. Side *side;
  86. Map *map;
  87. {
  88.     int found;
  89.  
  90.     side->ui->beepcount = 0;
  91.     /* Look through the X-specific command table. */
  92.     found = execute_command_from_table(side, map, xcommands);
  93.     if (!found) {
  94.     /* Try the generic table. */
  95.     found = execute_command_from_table(side, map, commands);
  96.     }
  97.     if (!found) {
  98.     cmd_error(side, "unknown command key '%c'", map->inpch);
  99.     }
  100. }
  101.  
  102. static int
  103. execute_command_from_table(side, map, cmdtab)
  104. Side *side;
  105. Map *map;
  106. CmdTab *cmdtab;
  107. {
  108.     CmdTab *cmd;
  109.     char ch = map->inpch;
  110.     void (*fn) PROTO ((Side *side, Map *map));
  111.     
  112.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  113.     if (ch == cmd->fchar) {
  114.         fn = cmd->fn;
  115.         if (fn == NULL) {
  116.         run_warning("no command function for %s (0x%x)?",
  117.                 cmd->name, ch);
  118.         return TRUE;
  119.         }
  120.         tmpkey = ch;
  121.         if (cmd->argtypes != NULL
  122.         && cmd->argtypes[0] == 'U'
  123.         && fn != do_delay /* hack */) {
  124.         if (map->curunit != NULL) {
  125.             (*fn)(side, map);
  126.         } else {
  127.             cmd_error(side, "No unit to command!");
  128.         }
  129.         } else {
  130.         (*fn)(side, map);
  131.         }
  132.         /* Whatever might have happened, we *did* find the command. */
  133.         return TRUE;
  134.     }
  135.     }
  136.     return FALSE;
  137. }
  138.  
  139. /* (should parse the command in useful ways) */
  140.  
  141. static void
  142. execute_named_command(side, map, cmdstr)
  143. Side *side;
  144. Map *map;
  145. char *cmdstr;
  146. {
  147.     int found;
  148.  
  149.     /* Look for the command name in the X-specific table. */
  150.     found = execute_named_command_from_table(side, map, cmdstr, xcommands);
  151.     if (!found) {
  152.     /* Try the generic table. */
  153.     found = execute_named_command_from_table(side, map, cmdstr, commands);
  154.     }
  155.     if (!found) {
  156.     cmd_error(side, "unrecognized command name \"%s\"", cmdstr);
  157.     }
  158. }
  159.  
  160. static int
  161. execute_named_command_from_table(side, map, cmdstr, cmdtab)
  162. Side *side;
  163. Map *map;
  164. char *cmdstr;
  165. CmdTab *cmdtab;
  166. {
  167.     CmdTab *cmd;
  168.     void (*fn) PROTO ((Side *side, Map *map));
  169.  
  170.     /* Whack off leading whitespace. */
  171.     while (*cmdstr && isspace(*cmdstr))
  172.       ++cmdstr;
  173.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  174.     if (strcmp(cmdstr, cmd->name) == 0) {
  175.         if ((fn = cmd->fn) == NULL) {
  176.         run_warning("no command function for %s?", cmd->name);
  177.         return TRUE;
  178.         }
  179.         tmpkey = cmd->fchar;
  180.         (*fn)(side, map);
  181.         /* Whatever might have happened, we *did* find the command. */
  182.         return TRUE;
  183.     }
  184.     }
  185.     return FALSE;
  186. }
  187.  
  188. /* Describe all the commands. */
  189.  
  190. static void
  191. describe_commands(arg, key, buf)
  192. int arg;
  193. char *key, *buf;
  194. {
  195.     describe_command_table(arg, key, buf, commands);
  196.     strcat(buf, "\n");
  197.     describe_command_table(arg, key, buf, xcommands);
  198. }
  199.  
  200. /* Describe all the commands to be found in a given table. */
  201.  
  202. static void
  203. describe_command_table(arg, key, buf, cmdtab)
  204. int arg;
  205. char *key, *buf;
  206. CmdTab *cmdtab;
  207. {
  208.     CmdTab *cmd;
  209.  
  210.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  211.     if (cmd->fchar != '\0') {
  212.         if (cmd->fchar < ' ' || cmd->fchar > '~') { 
  213.         tprintf(buf, "^%c", (cmd->fchar ^ 0x40));
  214.         } else {
  215.         tprintf(buf, " %c", cmd->fchar);
  216.         }
  217.         strcat(buf, " ");
  218.         strcat(buf, cmd->help);
  219.         strcat(buf, "\n");
  220.     }
  221.     }
  222.     for (cmd = cmdtab; cmd->name != NULL; ++cmd) {
  223.     if (cmd->fchar == '\0') {
  224.         strcat(buf, "\"");
  225.         strcat(buf, cmd->name);
  226.         strcat(buf, "\"");
  227.         strcat(buf, " ");
  228.         strcat(buf, cmd->help);
  229.         strcat(buf, "\n");
  230.     }
  231.     }
  232. }
  233.  
  234. /* Definitions of all the command functions. */
  235.  
  236. void
  237. do_add_player(side, map)
  238. Side *side;
  239. Map *map;
  240. {
  241.     notify(side, "can't add new players yet");
  242. }
  243.  
  244. void
  245. do_add_terrain(side, map)
  246. Side *side;
  247. Map *map;
  248. {
  249.     notify(side, "can't add terrain yet");
  250. }
  251.  
  252. void
  253. do_ai_side(side, map)
  254. Side *side;
  255. Map *map;
  256. {
  257.     if (side_has_ai(side)) {
  258.     set_side_ai(side, NULL);
  259.     } else {
  260.     set_side_ai(side, "mplayer");
  261.     }
  262. }
  263.  
  264. void
  265. do_attack(side, map)
  266. Side *side;
  267. Map *map;
  268. {
  269.     notify(side, "no generic attacks yet");
  270. }
  271.  
  272. void
  273. do_auto(side, map)
  274. Side *side;
  275. Map *map;
  276. {
  277.     Unit *unit = map->curunit;
  278.     
  279.     if (unit->plan) {
  280.     unit->plan->autotask = !unit->plan->autotask;
  281.     /* finish move under automatic control */
  282.     }
  283. }
  284.  
  285. void
  286. do_build(side, map)
  287. Side *side;
  288. Map *map;
  289. {
  290.     int n, u, u2, possibles[MAXUTYPES], numtypes, ufirst;
  291.     Unit *unit = map->curunit;
  292.  
  293.     u = unit->type;
  294.     if (!can_build(unit)) {
  295.     cmd_error(side, "This unit can't build anything!");
  296.     return;
  297.     }
  298.     if (unit->transport != NULL
  299.     && !uu_occ_can_build(unit->transport->type, u)) {
  300.     cmd_error(side, "This unit can't build anything while inside another unit!");
  301.     return;
  302.     }
  303.     numtypes = 0;
  304.     for_all_unit_types(u2) {
  305.     if (uu_acp_to_create(u, u2) > 0) {
  306.         possibles[u2] = 1;
  307.         ++numtypes;
  308.         ufirst = u2;
  309.     } else {
  310.         possibles[u2] = 0;
  311.     }
  312.     }
  313.     switch (numtypes) {
  314.       case 0:
  315.     cmd_error(side, "Nothing to build!");
  316.     break;
  317.       case 1:
  318.     /* Only one type to build - do it. */
  319.     n = map->argint;
  320.     if (n < 0)
  321.       n = 99;
  322.     notify(side, "%s will build %d %s",
  323.            unit_handle(side, unit), n, u_type_name(ufirst));
  324.     push_build_task(unit, ufirst, n);
  325.     break;
  326.       default:
  327.     /* Player has to choose a type to build. */
  328.     map->argunitid = unit->id;
  329.     ask_unit_type(side, map, "Type to build:", possibles, x_build);
  330.     break;
  331.     }
  332. }
  333.  
  334. static void
  335. x_build(side, map, cancel)
  336. Side *side;
  337. Map *map;
  338. int cancel;
  339. {
  340.     int u2, n;
  341.     Unit *unit;
  342.  
  343.     if (cancel)
  344.       return;
  345.     if (map->inpch == '?') {
  346.     notify(side, "Type a key or click on a unit type to select build.");
  347.     map->modalhandler = x_build;
  348.     return;
  349.     }
  350.     if (grok_unit_type(side, map, &u2)) {
  351.     if (u2 != NONUTYPE) {
  352.         unit = find_unit(map->argunitid);
  353.         if (in_play(unit) && side_controls_unit(side, unit)) {
  354.         n = map->argint;
  355.         if (n < 0)
  356.           n = 99;
  357.         notify(side, "%s will build %d %s",
  358.                unit_handle(side, unit), n, u_type_name(u2));
  359.         push_build_task(unit, u2, n);
  360.         }
  361.     }
  362.     } else {
  363.     /* beep? */
  364.     }
  365. }
  366.  
  367. void
  368. do_clear_plan(side, map)
  369. Side *side;
  370. Map *map;
  371. {
  372.     Unit *unit = map->curunit;
  373.  
  374.     set_unit_plan_type(side, unit, PLAN_NONE);
  375. }
  376.  
  377. void
  378. do_copying(side, map)
  379. Side *side;
  380. Map *map;
  381. {
  382.     notify(side, "You may copy freely.  See the file COPYING.");
  383. }
  384.  
  385. void
  386. do_delay(side, map)
  387. Side *side;
  388. Map *map;
  389. {
  390.     Unit *unit = map->curunit;
  391.  
  392.     if (unit != NULL) {
  393.     if (unit->plan)
  394.       delay_unit(unit, TRUE);
  395.     } else {
  396.     unit = find_next_awake_mover(side, map->curunit);
  397.     if (unit != map->curunit) {
  398.         set_current_unit(side, map, unit);
  399.     } else {
  400.         cmd_error(side, "No next awake mover found.");
  401.     }
  402.     }
  403. }
  404.  
  405. void
  406. do_detach(side, map)
  407. Side *side;
  408. Map *map;
  409. {
  410.     notify(side, "can't detach yet");
  411. }
  412.  
  413. void
  414. do_detonate(side, map)
  415. Side *side;
  416. Map *map;
  417. {
  418.     Unit *unit = map->curunit;
  419.  
  420.     prep_detonate_action(unit, unit, unit->x, unit->y, unit->z);
  421. }
  422.  
  423. void
  424. do_dir(side, map)
  425. Side *side;
  426. Map *map;
  427. {
  428.     switch (map->curtool) {
  429.       case looktool:
  430.     if (map->argint < 0)
  431.       map->argint = 1;
  432.     x_move_look(side, map);
  433.     break;
  434.       case movetool:
  435.       case unitmovetool:
  436.     if (map->curunit != NULL) {
  437.         x_move_dir(side, map, map->curunit);
  438.     } else {
  439.         cmd_error(side, "No unit to move!");
  440.     }
  441.     break;
  442.     }
  443. }
  444.  
  445. void
  446. do_dir_multiple(side, map)
  447. Side *side;
  448. Map *map;
  449. {
  450.  
  451.     switch (map->curtool) {
  452.       case looktool:
  453.     if (map->argint < 0)
  454.       map->argint = 10;
  455.     x_move_look(side, map);
  456.     break;
  457.       case movetool:
  458.       case unitmovetool:
  459.     map->argint = 9999;
  460.     if (map->curunit != NULL) {
  461.         x_move_dir(side, map, map->curunit);
  462.     } else {
  463.         cmd_error(side, "No unit to move!");
  464.     }
  465.     break;
  466.     }
  467. }
  468.  
  469. static void
  470. x_move_look(side, map)
  471. Side *side;
  472. Map *map;
  473. {
  474.     char *dc;
  475.     int dir, nx, ny;
  476.     Unit *unit;
  477.  
  478.     dc = strchr(dirchars, tmpkey);
  479.     if (dc == NULL) {
  480.     dc = strchr(dirchars, lowercase(tmpkey));
  481.     if (dc == NULL) {
  482.         cmd_error(side, "what direction is that?!?");
  483.         return;
  484.     }
  485.     }
  486.     dir = dc - dirchars;
  487.     if (!point_in_dir_n(map->curx, map->cury, dir, map->argint, &nx, &ny)) {
  488.     beep(side);
  489.     return;
  490.     }
  491.     /* (should share with move_look) */
  492.     clear_current(side, map);
  493.     unit = unit_at(nx, ny);
  494.     if (unit != NULL 
  495.     && (side_controls_unit(side, unit) || g_see_all())) {
  496.     set_current_unit(side, map, unit);
  497.     } else {
  498.     set_current_xy(side, map, nx, ny);
  499.     }
  500. }
  501.   
  502. static void
  503. x_move_dir(side, map, unit)
  504. Side *side;
  505. Map *map;
  506. Unit *unit;
  507. {
  508.     char *dc;
  509.     int dir;
  510.     int n = map->argint;
  511.     int x, y;
  512.   
  513.     dc = strchr(dirchars, tmpkey);
  514.     if (dc == NULL) {
  515.     dc = strchr(dirchars, lowercase(tmpkey));
  516.     if (dc == NULL) {
  517.         cmd_error(side, "what direction is that?!?");
  518.         return;
  519.     }
  520.     }
  521.     if (!unit->act || !unit->plan) { /* use a more sophisticated test? */
  522.     /* ??? can't act ??? */
  523.     return;
  524.     }
  525.     dir = dc - dirchars;
  526.     if (n > 1) {
  527.     DGprintf("Ordering %s to move %d %s\n",
  528.          unit_desig(unit), n, dirnames[dir]);
  529.     set_movedir_task(unit, dir, n);
  530.     } else {
  531.     if (!point_in_dir(unit->x, unit->y, dir, &x, &y)) {
  532.         return;
  533.     }
  534.     if (!advance_into_cell(side, unit, x, y, NULL)) {
  535.         beep(side);
  536.     }
  537.     if (in_play(unit)) {
  538.         map->curx = unit->x;  map->cury = unit->y;
  539.     }
  540.     /* make sure we don't wander too close to the edge... */
  541.     /* (this probably should not be here) */
  542.     x = map->curx - map->vx;  y = map->cury - map->vy;
  543.     if (y < 3 || y > map->vh - 3) {
  544.         recenter(side, map, map->curx, map->cury);
  545.     }
  546.     }
  547. }
  548.  
  549. /* Get rid of a unit. */
  550.  
  551. void
  552. do_disband(side, map)
  553. Side *side;
  554. Map *map;
  555. {
  556.     int u;
  557.     Unit *unit = map->curunit;
  558.  
  559.     if (!in_play(unit))
  560.       return;
  561.     u = unit->type;
  562. #ifdef DESIGNERS
  563.     /* A designer can take out any unit, no questions asked. */
  564.     if (side->designer) {
  565.     kill_unit(unit, -1);
  566.     return;
  567.     }
  568. #endif /* DESIGNERS */
  569.     if (u_hp_per_disband(u) > 0) {
  570.     if (prep_disband_action(unit, unit)) {
  571.         notify(side, "%s will go home.", unit_handle(side, unit));
  572.     } else {
  573.         cmd_error(side, "odd failure");
  574.     }
  575.     } else {
  576.     cmd_error(side, "You can't just get rid of the %s!", u_type_name(u));
  577.     }
  578. }
  579.  
  580. void
  581. do_distance(side, map)
  582. Side *side;
  583. Map *map;
  584. {
  585.     save_cur(side, map);
  586.     ask_position(side, map, "Distance to where?", x_distance);
  587. }
  588.  
  589. static void
  590. x_distance(side, map, cancel)
  591. Side *side;
  592. Map *map;
  593. int cancel;
  594. {
  595.     int x, y, dist;
  596.  
  597.     if (cancel)
  598.       return;
  599.     if (map->inpch == '?') {
  600.     notify(side, "Not being helpful yet.");
  601.     map->modalhandler = x_distance;
  602.     return;
  603.     }
  604.     if (grok_position(side, map, &x, &y)) {
  605.     if (in_area(x, y)) {
  606.         dist = distance(map->savedcurx, map->savedcury, x, y);
  607.         notify(side, "The distance is %d cells.", dist);
  608.     }
  609.     restore_cur(side, map);
  610.     } else {
  611.     map->modalhandler = x_distance;
  612.     /* beep? */
  613.     }
  614. }
  615.  
  616. void
  617. do_end_turn(side, map)
  618. Side *side;
  619. Map *map;
  620. {
  621.     finish_turn(side);
  622. }
  623.  
  624. void
  625. do_fire(side, map)
  626. Side *side;
  627. Map *map;
  628. {
  629.     int sx, sy, x, y;
  630.     Map *map2;
  631.     Unit *other;
  632.     Unit *unit = map->curunit;
  633.  
  634.     if (!in_play(unit))
  635.       return;
  636.  
  637.     sx = side->ui->sxdown;
  638.     sy = side->ui->sydown;
  639.     map2 = side->ui->mapdown;
  640.  
  641.     if (x_nearest_cell(side, map2, sx, sy, &x, &y)) {
  642.     if (x != unit->x || y != unit->y) {
  643.         if (unit->act && unit->plan) { /* (should be more sophisticated?) */
  644.         other = unit_at(x, y);
  645.         if (other != NULL) {
  646.             /* There's a unit to fire at. */
  647.             if (other->side == unit->side) {
  648.             beep(side);
  649.             } else {
  650.             prep_fire_at_action(unit, unit, other, -1);
  651.             }
  652.         } else {
  653.             beep(side);
  654.         }
  655.         }
  656.     }
  657.     }
  658. }
  659.  
  660. void
  661. do_fire_into(side, map)
  662. Side *side;
  663. Map *map;
  664. {
  665.     beep(side);
  666. }
  667.  
  668. void
  669. do_give(side, map)
  670. Side *side;
  671. Map *map;
  672. {
  673.     int something = FALSE;
  674.     int n, u, m, r, gift, actual;
  675.     Unit *unit = map->curunit, *main = NULL;
  676.     char buf[BUFSIZE];
  677.  
  678.     if (nummtypes == 0) {
  679.     cmd_error(side, "No materials in this game!");
  680.     return;
  681.     }
  682.     buf[0] = '\0';
  683.     u = unit->type;
  684.     main = unit->transport;
  685.     if (main == NULL) {
  686.     cmd_error(side, "Nothing to give to here!");
  687.     return;
  688.     }
  689.     m = main->type;
  690.     n = (map->argint < 0 ? 1 : map->argint);
  691.  
  692.     for_all_material_types(r) {
  693.     gift = (n < 0 ? (um_storage_x(m, r) - main->supply[r]) : n);
  694.     if (gift > 0) {
  695.         something = TRUE;
  696.         /* Be stingy if we're low */
  697.         if (2 * unit->supply[r] < um_storage_x(u, r))
  698.           gift = max(1, gift/2);
  699.         actual = transfer_supply(unit, main, r, gift);
  700.         tprintf(buf, " %d %s", actual, m_type_name(r));
  701.     }
  702.     }
  703.     if (something) {
  704.     notify(side, "%s gave%s.", unit_handle(side, unit), buf);
  705.     } else {
  706.     notify(side, "%s gave nothing.", unit_handle(side, unit));
  707.     }
  708. }
  709.  
  710. /* Give a unit to another side or make it independent. */
  711.  
  712. /* (but giving to indep should be tested, otherwise might kill unit) */
  713.  
  714. void
  715. do_give_unit(side, map)
  716. Side *side;
  717. Map *map;
  718. {
  719.     int u;
  720.     Unit *unit = map->curunit;
  721.  
  722.     u = unit->type;
  723.     if (/* u_change_side(u) || */ side->designer) {
  724. /*    unit_changes_side(unit, side_n(n), CAPTURE, PRISONER);  */
  725.     all_see_cell(unit->x, unit->y);
  726.     } else {
  727.     cmd_error(side, "You can't just give away the %s!", u_type_name(u));
  728.     }
  729. }
  730.  
  731. void
  732. do_help(side, map)
  733. Side *side;
  734. Map *map;
  735. {
  736.     /* Compose the help node for commands and make it be the first one. */
  737.     if (side->ui->curhelpnode == NULL) {
  738.     add_help_node("commands", describe_commands, 0, firsthelpnode);
  739.     side->ui->curhelpnode = firsthelpnode;
  740.     }
  741.     popup_help(side);
  742. }
  743.  
  744. /* Send a short (1 line) message to another player.  Some messages are
  745.    recognized specially, causing various actions. */
  746.  
  747. void
  748. do_message(side, map)
  749. Side *side;
  750. Map *map;
  751. {
  752.     char prompt[BUFSIZE];
  753.     Side *side2;
  754.  
  755.     side2 = side_n(map->argint);
  756.     if (side == side2) {
  757.     cmd_error(side, "You mumble to yourself.");
  758.     return;
  759.     }
  760.     if (side2) {
  761.     sprintf(prompt, "Say to %s: ", short_side_title(side2));
  762.     } else {
  763.     sprintf(prompt, "Broadcast to all: ");
  764.     }
  765.     map->argside = side2;
  766.     ask_string(side, map, prompt, NULL, x_message);
  767. }
  768.  
  769. static void
  770. x_message(side, map, cancel)
  771. Side *side;
  772. Map *map;
  773. int cancel;
  774. {
  775.     char *msg;
  776.     SideMask sidemask;
  777.  
  778.     if (cancel)
  779.       return;
  780.     if (grok_string(side, map, &msg)) {
  781.     if (empty_string(msg)) {
  782.         notify(side, "You keep your mouth shut.");
  783.         sidemask = NOSIDES;
  784.     } else if (map->argside == NULL) {
  785.         notify(side, "You made the announcement \"%s\"", msg);
  786.         sidemask = ALLSIDES;
  787.     } else {
  788.         notify(side, "Your message was sent.");
  789.         sidemask = add_side_to_set(map->argside, NOSIDES);
  790.     }
  791.     if (!empty_string(msg) && sidemask != NOSIDES)
  792.       send_message(side, sidemask, msg);
  793.     } else {
  794.     map->modalhandler = x_message;
  795.     }
  796. }
  797.  
  798. /* Set unit to move to a given location.  */
  799.  
  800. /* The command proper. */
  801.  
  802. void
  803. do_move_to(side, map)
  804. Side *side;
  805. Map *map;
  806. {
  807.     Unit *unit = map->curunit;
  808.  
  809.     map->argunitid = unit->id;
  810.     save_cur(side, map);
  811.     ask_position(side, map, "Move to where?", x_move_to);
  812. }
  813.  
  814. static void
  815. x_move_to(side, map, cancel)
  816. Side *side;
  817. Map *map;
  818. int cancel;
  819. {
  820.     int x, y;
  821.     Unit *unit;
  822.  
  823.     if (cancel)
  824.       return;
  825.     if (grok_position(side, map, &x, &y)) {
  826.     unit = find_unit(map->argunitid);
  827. #ifdef DESIGNERS
  828.     if (side->designer) {
  829.         designer_teleport(unit, x, y);
  830.     } else
  831. #endif /* DESIGNERS */
  832.     if (in_play(unit)) {
  833.         set_moveto_task(unit, x, y);
  834.     } else {
  835.         beep(side);
  836.     }
  837.     restore_cur(side, map);
  838.     } else {
  839.     map->modalhandler = x_move_to;
  840.     }
  841. }
  842.  
  843. /* Name/rename the current unit. */
  844.  
  845. void
  846. do_name(side, map)
  847. Side *side;
  848. Map *map;
  849. {
  850.     char tmpbuf[BUFSIZE];
  851.     Unit *unit = map->curunit;
  852.  
  853.     map->argunitid = unit->id;
  854.     sprintf(tmpbuf, "New name for %s:", unit_handle(side, unit));
  855.     ask_string(side, map, tmpbuf, unit->name, x_name);
  856. }
  857.  
  858. static void
  859. x_name(side, map, cancel)
  860. Side *side;
  861. Map *map;
  862. int cancel;
  863. {
  864.     char *name;
  865.     Unit *unit;
  866.  
  867.     if (cancel)
  868.       return;
  869.     if (grok_string(side, map, &name)) {
  870.     unit = find_unit(map->argunitid);
  871.     if (in_play(unit) && side_controls_unit(side, unit)) {
  872.         set_unit_name(side, unit, name);
  873.     } else {
  874.         cmd_error(side, "Nothing could be named!");
  875.     }
  876.     } else {
  877.     map->modalhandler = x_name;
  878.     }
  879. }
  880.  
  881. /* This is a command to examine all occupants and suboccupants, in an
  882.    inorder fashion. */
  883.  
  884. /* Should have an option to open up a list window that shows everything
  885.    all at once. */
  886.  
  887. void
  888. do_occupant(side, map)
  889. Side *side;
  890. Map *map;
  891. {
  892.     Unit *nextup;
  893.     Unit *unit = map->curunit;
  894.  
  895.     if (unit->occupant != NULL) {
  896.     set_current_unit(side, map, unit->occupant);
  897.     } else if (unit->nexthere != NULL) {
  898.     set_current_unit(side, map, unit->nexthere);
  899.     } else {
  900.     nextup = unit->transport;
  901.     if (nextup != NULL) {
  902.         while (nextup->transport != NULL && nextup->nexthere == NULL) {
  903.         nextup = nextup->transport;
  904.         }
  905.         if (nextup->nexthere != NULL)
  906.           set_current_unit(side, map, nextup->nexthere);
  907.         if (nextup->transport == NULL)
  908.           set_current_unit(side, map, nextup);
  909.     } else {
  910.         /* This is a no-op if there is no stacking within a hex. */
  911.         set_current_unit(side, map, unit_at(unit->x, unit->y));
  912.     }
  913.     }
  914. }
  915.  
  916. void
  917. do_other(side, map)
  918. Side *side;
  919. Map *map;
  920. {
  921.     ask_string(side, map, "Command:", "", x_others);
  922. }
  923.  
  924. static void
  925. x_others(side, map, cancel)
  926. Side *side;
  927. Map *map;
  928. int cancel;
  929. {
  930.     char *cmd;
  931.  
  932.     if (cancel)
  933.       return;
  934.     if (grok_string(side, map, &cmd)) {
  935.     if (empty_string(cmd)) {
  936.         notify(side, "No command");
  937.     } else if (strcmp(cmd, "?") == 0) {
  938.         do_help(side, map);
  939.         /* (should go to command list specifically) */
  940.     } else {
  941.         execute_named_command(side, map, cmd);
  942.     }
  943.     } else {
  944.     map->modalhandler = x_others;
  945.     }
  946. }
  947.  
  948. static PrintParameters *ps_pp = NULL;
  949.  
  950. void
  951. do_print_view(side, map)
  952. Side *side;
  953. Map *map;
  954. {  
  955.     double conv;
  956.  
  957.     if (!ps_pp)
  958.       ps_pp = (PrintParameters *) xmalloc(sizeof(PrintParameters));
  959.  
  960.     init_ps_print(ps_pp);
  961.  
  962.     /* convert to cm or in */
  963.     if (ps_pp->cm) {
  964.     conv = 72/2.54;
  965.     } else {
  966.     conv = 72;
  967.     }
  968.     ps_pp->cell_size /= conv;
  969.     ps_pp->cell_grid_width /= conv;
  970.     ps_pp->border_width /= conv;
  971.     ps_pp->connection_width /= conv;
  972.     ps_pp->page_width /= conv;
  973.     ps_pp->page_height /= conv;
  974.     ps_pp->top_margin /= conv;
  975.     ps_pp->bottom_margin /= conv;
  976.     ps_pp->left_margin /= conv;
  977.     ps_pp->right_margin /= conv;
  978.  
  979.     popup_print_setup_dialog(side, ps_pp);
  980. #if 0
  981.     /* dump the view */    
  982.         notify(side, "dumping view to file \"view.xconq\" ...");
  983.         flush_output(side);
  984.     dump_ps_view(side, ps_pp, "view.xconq");
  985.     notify(side, "... done.");
  986. #endif
  987. }
  988.  
  989. void
  990. do_produce(side, map)
  991. Side *side;
  992. Map *map;
  993. {
  994.     notify(side, "not available yet");
  995. }
  996.  
  997. void
  998. do_quit(side, map)
  999. Side *side;
  1000. Map *map;
  1001. {
  1002.     if (side->ingame) {
  1003.     if (all_others_willing_to_quit(side)) {
  1004.         /* Everbody else is willing to get out, but confirm us anyway. */
  1005.         ask_bool(side, map, "Do you really want to quit?", FALSE,
  1006.              x_kill_game);
  1007.     } else {
  1008.         if (1 /* outcome needs resolution */) {
  1009.         /* if not everybody willing to draw, then we have to resign */
  1010.         ask_bool(side, map, "Do you really want to give up?", FALSE,
  1011.              x_resign);
  1012.         } else {
  1013.         /* Everybody is just participating. */
  1014.         ask_bool(side, map, "Do you want to leave this game?", FALSE,
  1015.              x_leave_game);
  1016.         }
  1017.     }
  1018.     } else {
  1019.     /* We're already out of the game, not really anything to confirm. */
  1020.     /* (is this common to all interfaces?) */
  1021.     if (all_others_willing_to_quit(side)) {
  1022.         exit_xconq(side);
  1023.     } else {
  1024.         close_display(side);
  1025.         if (num_active_displays() == 0) {
  1026.         exit_xconq(side);
  1027.         }
  1028.     }
  1029.     }
  1030. }
  1031.  
  1032. static void
  1033. x_resign(side, map, cancel)
  1034. Side *side;
  1035. Map *map;
  1036. int cancel;
  1037. {
  1038.     if (cancel)
  1039.       return;
  1040.     if (grok_bool(side, map)) {
  1041.     if (numsides > 2) {
  1042.         ask_side(side, map, "Who do you want to surrender to?", NULL,
  1043.              x_resign_2);
  1044.     } else {
  1045.         resign_game(side, NULL);
  1046.     }
  1047.     }
  1048. }
  1049.  
  1050. static void
  1051. x_resign_2(side, map, cancel)
  1052. Side *side;
  1053. Map *map;
  1054. int cancel;
  1055. {
  1056.     Side *side2;
  1057.  
  1058.     if (cancel)
  1059.       return;
  1060.     grok_side(side, map, &side2);
  1061.     resign_game(side, side2);
  1062. }
  1063.  
  1064. /* Do the act of leaving the game. */
  1065.  
  1066. static void
  1067. x_leave_game(side, map, cancel)
  1068. Side *side;
  1069. Map *map;
  1070. int cancel;
  1071. {
  1072.     if (cancel)
  1073.       return;
  1074.     if (grok_bool(side, map)) {
  1075.     remove_side_from_game(side);
  1076.     /* Now go back and see what happens if we're not in the game. */ 
  1077.     do_quit(side, NULL);
  1078.     } else {
  1079.     /* nothing to do if we said not to exit */
  1080.     }
  1081. }
  1082.  
  1083. /* (Have an extra confirm for designers not to lose unsaved work?) */
  1084.  
  1085. static void
  1086. x_kill_game(side, map, cancel)
  1087. Side *side;
  1088. Map *map;
  1089. int cancel;
  1090. {
  1091.     if (cancel)
  1092.       return;
  1093.     if (grok_bool(side, map)) {
  1094.     exit_xconq(side);
  1095.     } else {
  1096.     /* nothing to do if we said not to exit */
  1097.     }
  1098. }
  1099.  
  1100. /* Center the screen on the current location. */
  1101.  
  1102. void
  1103. do_recenter(side, map)
  1104. Side *side;
  1105. Map *map;
  1106. {
  1107.     recenter(side, map, map->curx, map->cury);
  1108. }
  1109.  
  1110. /* Redraw everything using the same code as when windows need a redraw. */
  1111.  
  1112. void
  1113. do_refresh(side, map)
  1114. Side *side;
  1115. Map *map;
  1116. {
  1117.     redraw(side);
  1118.     draw_view_in_panner(side, map);
  1119. }
  1120.  
  1121. void
  1122. do_remove_terrain(side, map)
  1123. Side *side;
  1124. Map *map;
  1125. {
  1126.     notify(side, "can't remove terrain yet");
  1127. }
  1128.  
  1129. void
  1130. do_reserve(side, map)
  1131. Side *side;
  1132. Map *map;
  1133. {
  1134.     Unit *unit = map->curunit;
  1135.  
  1136.     set_unit_reserve(side, unit, TRUE, TRUE /* is this right??? */);
  1137. }
  1138.  
  1139. /* Set up a task to resupply the unit. */
  1140.  
  1141. /* (should warn if task is likely to fail) */
  1142.  
  1143. void
  1144. do_return(side, map)
  1145. Side *side;
  1146. Map *map;
  1147. {
  1148.     Unit *unit = map->curunit;
  1149.  
  1150.     /* (should doublecheck range and error out if no chance) */
  1151.     if (in_play(unit)) {
  1152.     set_resupply_task(unit);
  1153.     }
  1154. }
  1155.  
  1156. /* Stuff game state into a file.  By default, it goes into the current
  1157.    directory.  If designing a game, we can specify exactly which parts
  1158.    of the game state are to be written. */
  1159.  
  1160. /* The command proper just sets up different modal handlers, depending on
  1161.    whether we're building (and therefore saving a scenario/fragment), or
  1162.    saving as much game state as possible, for resumption later. */
  1163.  
  1164. void
  1165. do_save(side, map)
  1166. Side *side;
  1167. Map *map;
  1168. {
  1169.     Side *side2;
  1170.  
  1171.     /* First check to see if anybody is in the middle of doing something
  1172.        (like renaming a unit) whose state would be lost. */
  1173.     for_all_sides(side2) {
  1174.     if (side2 != side && side2->busy) {
  1175.         cmd_error(side, 
  1176.               "The %s are busy doing something, can't save right now!",
  1177.               plural_form(side2->name));
  1178.     }
  1179.     }
  1180. #ifdef DESIGNERS
  1181.     if (side->designer) {
  1182.     ask_string(side, map, "Types of data to save?", "all",
  1183.            x_save_1);
  1184.     return;
  1185.     }
  1186. #endif /* DESIGNERS */
  1187.     if (0 /* (should be "savemustquit") */) {
  1188.     ask_bool(side, map, "You really want to save?", FALSE, x_save_2);
  1189.     } else {
  1190.     save_the_game(side);
  1191.     }
  1192. }
  1193.  
  1194. /* Make a module appropriate to a save file, write the file, and leave. */
  1195.  
  1196. static void
  1197. x_save_2(side, map, cancel)
  1198. Side *side;
  1199. Map *map;
  1200. int cancel;
  1201. {
  1202.     if (cancel)
  1203.       return;
  1204.     if (grok_bool(side, map)) {
  1205.     save_the_game(side);
  1206.     }
  1207. }
  1208.  
  1209. static void
  1210. save_the_game(side)
  1211. Side *side;
  1212. {
  1213.     char *savename = saved_game_filename();
  1214.  
  1215.     notify_all("Game will be saved to \"%s\" ...", savename);
  1216.     if (write_entire_game_state(savename)) {
  1217.     close_displays();
  1218.     /* this should be conditional? */
  1219.     exit(0);
  1220.     } else {
  1221.     cmd_error(side, "Can't open file \"%s\"!", savename);
  1222.     }
  1223. }
  1224.  
  1225.  
  1226. #ifdef DESIGNERS
  1227.  
  1228. Module *tmpmodule;
  1229.  
  1230. static void
  1231. x_save_1_1(side, map, cancel)
  1232. Side *side;
  1233. Map *map;
  1234. int cancel;
  1235. {
  1236.     char *filenamespec;
  1237.  
  1238.     if (cancel)
  1239.       return;
  1240.     if (grok_string(side, map, &filenamespec)) {
  1241.     tmpmodule->filename = filenamespec;
  1242.     notify(side, "File will be written to \"%s\" ...",
  1243.            tmpmodule->filename);
  1244.     if (write_game_module(tmpmodule)) {
  1245.         notify(side, "Done writing to \"%s\".", tmpmodule->filename);
  1246.     } else {
  1247.         cmd_error(side, "Can't open file \"%s\"!", tmpmodule->filename);
  1248.     }
  1249.     } else {
  1250.     map->modalhandler = x_save_1_1;
  1251.     }
  1252. }
  1253.  
  1254. static void
  1255. x_save_1(side, map, cancel)
  1256. Side *side;
  1257. Map *map;
  1258. int cancel;
  1259. {
  1260.     int save;
  1261.     char *contentspec;
  1262.  
  1263.     if (cancel)
  1264.       return;
  1265.     if (grok_string(side, map, &contentspec)) {
  1266.     tmpmodule = create_game_module("game-data");
  1267.     /* Use the spec string to decide which pieces to save. */
  1268.     save = FALSE;
  1269.     if (strcmp(contentspec, "all") == 0) {
  1270.         tmpmodule->defall = TRUE;
  1271.         tmpmodule->compresslayers = TRUE;
  1272.         save = TRUE;
  1273.     } else if (strcmp(contentspec, "world") == 0) {
  1274.         tmpmodule->defworld = TRUE;
  1275.         tmpmodule->defareas = TRUE;
  1276.         tmpmodule->defareaterrain = TRUE;
  1277.         tmpmodule->defareamisc = TRUE;
  1278.         tmpmodule->defareaweather = TRUE;
  1279.         tmpmodule->defareamaterial = TRUE;
  1280.         save = TRUE;
  1281.     } else {
  1282.         cmd_error(side, "Don't understand content spec \"%s\"!",
  1283.               contentspec);
  1284.         return;
  1285.     }
  1286.     if (save) {
  1287.         ask_string(side, map, "Save data to where?", "game-data.g",
  1288.                x_save_1_1);
  1289.     } else {
  1290.         notify(side, "Nothing requested to be saved.");
  1291.     }
  1292.     } else {
  1293.     map->modalhandler = x_save_1;
  1294.     }
  1295. }
  1296.  
  1297. #endif /* DESIGNERS */
  1298.  
  1299. void
  1300. do_set_formation(side, map)
  1301. Side *side;
  1302. Map *map;
  1303. {
  1304.     beep(side);
  1305. }
  1306.  
  1307. void
  1308. do_sleep(side, map)
  1309. Side *side;
  1310. Map *map;
  1311. {
  1312.     Unit *unit = map->curunit;
  1313.  
  1314.     set_unit_asleep(side, unit, TRUE, TRUE /* is this right??? */);
  1315. }
  1316.  
  1317. void
  1318. do_survey(side, map)
  1319. Side *side;
  1320. Map *map;
  1321. {
  1322.     int i;
  1323.  
  1324.     if (map->curtool == looktool) {
  1325.     map->curtool = movetool;
  1326.     set_tool_cursor(side, map);
  1327.     update_controls(side, map);
  1328.     } else if (map->curtool == movetool) {
  1329.     map->curtool = looktool;
  1330.     set_tool_cursor(side, map);
  1331.     update_controls(side, map);
  1332.     } else {
  1333.     beep(side);
  1334.     }
  1335. }
  1336.  
  1337. /* Take supplies from transport. */
  1338.  
  1339. void
  1340. do_take(side, map)
  1341. Side *side;
  1342. Map *map;
  1343. {
  1344.     int something = FALSE;
  1345.     int u, u2, m, need, actual, n;
  1346.     Unit *unit = map->curunit, *unit2;
  1347.     char buf[BUFSIZE];
  1348.  
  1349.     if (nummtypes == 0) {
  1350.     cmd_error(side, "No materials in this game!");
  1351.     return;
  1352.     }
  1353.     if (!in_play(unit))
  1354.       return;
  1355.     u = unit->type;
  1356.     unit2 = unit->transport;
  1357.     if (unit2 == NULL) {
  1358.     cmd_error(side, "Nothing to take from here!");
  1359.     return;
  1360.     }
  1361.     u2 = unit2->type;
  1362.     n = (map->argint < 0 ? 1 : map->argint);
  1363.  
  1364.     buf[0] = '\0';
  1365.     for_all_material_types(m) {
  1366.     need = (n < 0 ? um_storage_x(u, m) - unit->supply[m] : n);
  1367.     if (need > 0) {
  1368.         something = TRUE;
  1369.         /* Be stingy if we're low */
  1370.         if (2 * unit2->supply[m] < um_storage_x(u2, m))
  1371.           need = max(1, need/2);
  1372.         actual = transfer_supply(unit2, unit, m, need);
  1373.         tprintf(buf, " %d %s", actual, m_type_name(m));
  1374.     }
  1375.     }
  1376.     if (something) {
  1377.     notify(side, "%s got%s.", unit_handle(side, unit), buf);
  1378.     } else {
  1379.     notify(side, "%s needed nothing.", unit_handle(side, unit));
  1380.     }
  1381. }
  1382.  
  1383. void
  1384. do_take_unit(side, map)
  1385. Side *side;
  1386. Map *map;
  1387. {
  1388.     notify(side, "not available yet");
  1389. }
  1390.  
  1391. /* Command to display the program version. */
  1392.  
  1393. void
  1394. do_version(side, map)
  1395. Side *side;
  1396. Map *map;
  1397. {
  1398.     notify(side, "Xconq version %s", version_string());
  1399.     notify(side, "(c) %s", copyright_string());
  1400. }
  1401.  
  1402. void
  1403. do_wake(side, map)
  1404. Side *side;
  1405. Map *map;
  1406. {
  1407.     /* Do the curunit explicitly, might only be an occupant. */
  1408.     if (map->curunit != NULL) {
  1409.     wake_unit(map->curunit, FALSE, 0, NULL);
  1410.     draw_map_info(side, map);
  1411.     }
  1412.     /* If an argument was given, apply to all "top-level" units
  1413.        within the radius specified by the argument. */
  1414.     if (map->argint >= 0)
  1415.       wake_area(side, map->curx, map->cury, map->argint, FALSE);
  1416. }
  1417.  
  1418. void
  1419. do_wake_all(side, map)
  1420. Side *side;
  1421. Map *map;
  1422. {
  1423.     int n;
  1424.  
  1425.     n = (map->argint < 0 ? 0 : map->argint);
  1426.     wake_area(side, map->curx, map->cury, n, TRUE);
  1427. }
  1428.  
  1429. void
  1430. do_warranty(side, map)
  1431. Side *side;
  1432. Map *map;
  1433. {
  1434.     notify(side, "There is no warranty.");
  1435. }
  1436.  
  1437. /* X-interface-specific commands. */
  1438.  
  1439. void
  1440. do_embark_cmd(side, map)
  1441. Side *side;
  1442. Map *map;
  1443. {
  1444.     Unit *transport, *occ;
  1445.     Unit *unit = map->curunit;
  1446.  
  1447.     if (!in_play(unit))
  1448.       return;
  1449.     /* look for the first possible transport */
  1450.     for_all_stack(unit->x, unit->y, transport) {
  1451.     /* make sure its not the transport we're in and we can enter it */
  1452.     if (transport != unit->transport &&
  1453.         valid(check_enter_action(unit, unit, transport))) {
  1454.         prep_enter_action(unit, unit, transport);
  1455.         return;
  1456.     }
  1457.  
  1458.     /* check the occupants too */
  1459.     for_all_occupants(transport, occ) {
  1460.         if (occ != unit->transport &&
  1461.         valid(check_enter_action(unit, unit, occ))) {
  1462.         prep_enter_action(unit, unit, occ);
  1463.         return;
  1464.         }
  1465.     }
  1466.     }
  1467.     cmd_error(side, "Nothing for this unit to get into!");
  1468. }
  1469.  
  1470. /* Toggle the "follow-action" flag. */
  1471.  
  1472. void
  1473. do_x_follow_action(side, map)
  1474. Side *side;
  1475. Map *map;
  1476. {
  1477.     side->ui->followaction = !side->ui->followaction;
  1478. }
  1479.  
  1480. void
  1481. do_x_reverse_video(side, map)
  1482. Side *side;
  1483. Map *map;
  1484. {
  1485.     if (side->ui->monochrome) {
  1486.     side->ui->bonw = !side->ui->bonw;
  1487.     set_colors(side);
  1488.     reset_color_state(side);
  1489.     redraw(side);
  1490.     } else {
  1491.     cmd_error(side, "Reverse video is only for monochrome!");
  1492.     }
  1493. }
  1494.  
  1495. /* (should clone last map in list perhaps) */
  1496.  
  1497. void
  1498. do_x_map(side, map)
  1499. Side *side;
  1500. Map *map;
  1501. {
  1502.     Map *map2;
  1503.  
  1504.     map2 = create_map(side, 5, NULL);
  1505. }
  1506.  
  1507. void
  1508. do_x_world_map(side, map)
  1509. Side *side;
  1510. Map *map;
  1511. {
  1512.     Map *wmap;
  1513.  
  1514.     wmap = create_map(side, -1, NULL);
  1515. }
  1516.  
  1517. void
  1518. do_zoom_in(side, map)
  1519. Side *side;
  1520. Map *map;
  1521. {
  1522.     zoom_in_out(side, map, ZOOM_IN);
  1523. }
  1524.  
  1525. void
  1526. do_zoom_out(side, map)
  1527. Side *side;
  1528. Map *map;
  1529. {
  1530.     zoom_in_out(side, map, ZOOM_OUT);
  1531. }
  1532.  
  1533. #ifdef DESIGNERS
  1534.  
  1535. static void x_design PROTO ((Side *side, Map *map, int cancel));
  1536. static void x_set_terrain_type PROTO ((Side *side, Map *map, int cancel));
  1537. static void x_set_unit_type PROTO ((Side *side, Map *map, int cancel));
  1538. static int check_designer_status PROTO ((Side *side, char *str));
  1539.  
  1540. int designed_on = FALSE;
  1541.  
  1542. void enable_in_unit_type_list PROTO ((Side *side, Map *map, int u, int flag));
  1543.  
  1544. static void really_do_design PROTO ((Side *side));
  1545.  
  1546. void
  1547. do_design(side, map)
  1548. Side *side;
  1549. Map *map;
  1550. {
  1551.     int u;
  1552.     Map *map2;
  1553.  
  1554.     if (!side->designer) {
  1555.     if (!designed_on) {
  1556.         ask_bool(side, map, "Do you really want to start designing?",
  1557.              FALSE, x_design);
  1558.     } else {
  1559.         really_do_design(side);
  1560.     }
  1561.     } else {
  1562.     become_nondesigner(side);
  1563.     side->ui->mayseeall = (g_see_all() || endofgame);
  1564.     for_all_maps(side, map2) {
  1565.         map2->seeall = side->ui->mayseeall;
  1566.         update_controls(side, map2);
  1567.         for_all_unit_types(u) {
  1568.         enable_in_unit_type_list(side, map2, u, FALSE);
  1569.         }
  1570.     }
  1571.     popdown_design(side);
  1572.     }
  1573. }
  1574.  
  1575. static void
  1576. x_design(side, map, cancel)
  1577. Side *side;
  1578. Map *map;
  1579. int cancel;
  1580. {
  1581.     if (cancel)
  1582.       return;
  1583.     if (grok_bool(side, map)) {
  1584.     really_do_design(side);
  1585.     } else {
  1586.     /* nothing to do if we said not to design */
  1587.     }
  1588. }
  1589.  
  1590. static void
  1591. really_do_design(side)
  1592. Side *side;
  1593. {
  1594.     int u;
  1595.     Map *map2;
  1596.  
  1597.     become_designer(side);
  1598.     side->ui->mayseeall = TRUE;
  1599.     for_all_maps(side, map2) {
  1600.     map2->seeall = side->ui->mayseeall;
  1601.     update_controls(side, map2);
  1602.     for_all_unit_types(u) {
  1603.         enable_in_unit_type_list(side, map2, u, TRUE);
  1604.     }
  1605.     }
  1606.     popup_design(side);
  1607. }
  1608.  
  1609. static int
  1610. check_designer_status(side, str)
  1611. Side *side;
  1612. char *str;
  1613. {
  1614.     if (side->designer) {
  1615.     return TRUE;
  1616.     } else {
  1617.     cmd_error(side, "You're not a designer, can't %s!", str);
  1618.     return FALSE;
  1619.     }
  1620. }
  1621.  
  1622. void
  1623. do_x_set_terrain_type(side, map)
  1624. Side *side;
  1625. Map *map;
  1626. {
  1627.     int n = 0;
  1628.     int numtypes;
  1629.  
  1630.     if (!check_designer_status(side, "set terr paint type"))
  1631.       return;
  1632.     numtypes = ask_terrain_type(side, map, "Type to paint: ", NULL,
  1633.                 x_set_terrain_type);
  1634.     switch (numtypes) {
  1635.       case 0:
  1636.     beep(side);
  1637.     break;
  1638.       case 1:
  1639.     side->ui->curttype = map->tvec[0];
  1640.     if (map->argint >= 0)
  1641.       side->ui->curbrushradius = map->argint;
  1642.     notify(side, "will now be painting %d-radius %s.",
  1643.            side->ui->curbrushradius, t_type_name(side->ui->curttype));
  1644.     break;
  1645.       default:
  1646.     break;
  1647.     }
  1648. }
  1649.  
  1650. static void
  1651. x_set_terrain_type(side, map, cancel)
  1652. Side *side;
  1653. Map *map;
  1654. int cancel;
  1655. {
  1656.     int t2;
  1657.  
  1658.     if (cancel)
  1659.       return;
  1660.     if (map->inpch == '?') {
  1661.     notify(side, "Not being helpful yet.");
  1662.     map->modalhandler = x_set_terrain_type;
  1663.     return;
  1664.     }
  1665.     if (grok_terrain_type(side, map, &t2)) {
  1666.     if (t2 != NONUTYPE) {
  1667.         side->ui->curttype = t2;
  1668.         if (map->argint >= 0)
  1669.           side->ui->curbrushradius = map->argint;
  1670.         notify(side, "will now be painting %d-radius %s.",
  1671.            side->ui->curbrushradius, t_type_name(side->ui->curttype));
  1672.     }
  1673.     } else {
  1674.     /* beep? */
  1675.     }
  1676. }
  1677.  
  1678. /* Command to paint terrain. */
  1679.  
  1680. void
  1681. do_x_paint_terrain(side, map)
  1682. Side *side;
  1683. Map *map;
  1684. {
  1685.     if (!check_designer_status(side, "paint terrain"))
  1686.       return;
  1687.     paint_cell(side, map->curx, map->cury,
  1688.            side->ui->curbrushradius, side->ui->curttype);
  1689. }
  1690.  
  1691. /* Command to set the current unit type to create. */
  1692.  
  1693. void
  1694. do_x_set_unit_type(side, map)
  1695. Side *side;
  1696. Map *map;
  1697. {
  1698.     int numtypes;
  1699.  
  1700.     if (!check_designer_status(side, "set unit type"))
  1701.       return;
  1702.     numtypes = ask_unit_type(side, map, "Type to create: ", NULL,
  1703.                  x_set_unit_type);
  1704.     switch (numtypes) {
  1705.       case 0:
  1706.     beep(side);
  1707.     break;
  1708.       case 1:
  1709.     side->ui->curutype = map->uvec[0];
  1710.     if (map->argint >= 0)
  1711.       side->ui->cursidenumber = map->argint;
  1712.     notify(side, "will now be creating %s %s units",
  1713.            side_adjective(side_n(side->ui->curusidenumber)),
  1714.            u_type_name(side->ui->curutype));
  1715.     break;
  1716.       default:
  1717.     break;
  1718.     }
  1719. }
  1720.  
  1721. static void
  1722. x_set_unit_type(side, map, cancel)
  1723. Side *side;
  1724. Map *map;
  1725. int cancel;
  1726. {
  1727.     int u2;
  1728.  
  1729.     if (cancel)
  1730.       return;
  1731.     if (map->inpch == '?') {
  1732.     notify(side, "Not being helpful yet.");
  1733.     map->modalhandler = x_set_unit_type;
  1734.     return;
  1735.     }
  1736.     if (grok_unit_type(side, map, &u2)) {
  1737.     if (u2 != NONUTYPE) {
  1738.         side->ui->curutype = u2;
  1739.         if (map->argint >= 0)
  1740.           side->ui->cursidenumber = map->argint;
  1741.         notify(side, "will now be creating side %d %s units",
  1742.            side->ui->cursidenumber, u_type_name(side->ui->curutype));
  1743.     }
  1744.     } else {
  1745.     /* beep? */
  1746.     }
  1747. }
  1748.  
  1749. /* Command to create and place a unit. */
  1750.  
  1751. void
  1752. do_x_add_unit(side, map)
  1753. Side *side;
  1754. Map *map;
  1755. {
  1756.     Unit *unit;
  1757.  
  1758.     if (!check_designer_status(side, "create units"))
  1759.       return;
  1760.     unit = designer_create_unit(side,
  1761.                 side->ui->curutype, side->ui->cursidenumber,
  1762.                 map->curx, map->cury);
  1763.     if (unit != NULL) {
  1764.     set_current_unit(side, map, unit);
  1765.     } else {
  1766.     cmd_error(side, "Unit creation failed!");
  1767.     }
  1768. }
  1769.  
  1770. #endif /* DESIGNERS */
  1771.  
  1772. #ifdef DEBUGGING
  1773.  
  1774. /* Debugging-related commands. */
  1775.  
  1776. /* General debugging toggles. */
  1777.  
  1778. void
  1779. do_debug(side, map)
  1780. Side *side;
  1781. Map *map;
  1782. {
  1783. #ifndef Debug
  1784.     Debug = !Debug;
  1785. #endif
  1786. }
  1787.  
  1788. void
  1789. do_debugg(side, map)
  1790. Side *side;
  1791. Map *map;
  1792. {
  1793. #ifndef DebugG
  1794.     DebugG = !DebugG;
  1795. #endif
  1796.     XSynchronize(side->ui->dpy, DebugG);
  1797. }
  1798.  
  1799. void
  1800. do_debugm(side, map)
  1801. Side *side;
  1802. Map *map;
  1803. {
  1804. #ifndef DebugM
  1805.     DebugM = !DebugM;
  1806. #endif
  1807. }
  1808.  
  1809. /* Pretend to be a monochrome screen - use for comparing color
  1810.    and b/w appearance of screens. */
  1811.  
  1812. void
  1813. do_x_fake_mono(side, map)
  1814. Side *side;
  1815. Map *map;
  1816. {
  1817.     side->ui->monochrome = !side->ui->monochrome;
  1818.     side->ui->bonw = BLACKONWHITE;
  1819.     set_colors(side);
  1820.     reset_color_state(side);
  1821.     redraw(side);
  1822. }
  1823.  
  1824. #endif /* DEBUGGING */
  1825.  
  1826. /* Generic command error feedback. */
  1827.  
  1828. static void
  1829. #ifdef __STDC__
  1830. cmd_error(Side *side, char *fmt, ...)
  1831. #else
  1832. cmd_error(side, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
  1833. Side *side;
  1834. char *fmt;
  1835. long a1, a2, a3, a4, a5, a6, a7, a8, a9;
  1836. #endif
  1837. {
  1838.     char tmpnbuf[BUFSIZE];
  1839.  
  1840. #ifdef __STDC__
  1841.     {
  1842.     va_list ap;
  1843.  
  1844.     va_start(ap, fmt);
  1845.     vsprintf(tmpnbuf, fmt, ap);
  1846.     va_end(ap);
  1847.     }
  1848. #else
  1849.     sprintf(tmpnbuf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  1850. #endif
  1851.     low_notify(side, tmpnbuf);
  1852.     /* Only beep once, even if a command generates multiple error messages. */
  1853.     if (side->ui->beepcount++ < 1)
  1854.       beep(side);
  1855. }
  1856.